/*
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.matezk.dms.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.matezk.dms.common.context.UserContextHolder;
import cn.matezk.dms.system.enums.FileTypeEnum;
import cn.matezk.dms.system.mapper.FileMapper;
import cn.matezk.dms.system.model.entity.FileDO;
import cn.matezk.dms.system.model.query.FileQuery;
import cn.matezk.dms.system.model.req.FileReq;
import cn.matezk.dms.system.model.resp.FileResp;
import cn.matezk.dms.system.model.resp.FileStatisticsResp;
import cn.matezk.dms.system.service.FileService;
import cn.matezk.dms.system.service.StorageService;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.PutObjectRequest;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import top.continew.starter.extension.crud.model.query.PageQuery;
import top.continew.starter.extension.crud.model.query.SortQuery;
import top.continew.starter.extension.crud.model.resp.PageResp;
import top.continew.starter.extension.crud.service.impl.BaseServiceImpl;

import java.io.IOException;
import java.sql.Date;
import java.time.ZoneId;
import java.util.List;

/**
 * 文件业务实现
 *
 * @author Charles7c
 * @since 2023/12/23 10:38
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FileServiceImpl extends BaseServiceImpl<FileMapper, FileDO, FileResp, FileResp, FileQuery, FileReq> implements FileService {

    private final FileStorageService fileStorageService;
    @Resource
    private StorageService storageService;

    @Value("${oss.endpoint:}")
    private String endpoint;
    @Value("${oss.accessKeyId:}")
    private String accessKeyId;
    @Value("${oss.accessKeySecret:}")
    private String accessKeySecret;
    @Value("${oss.bucket:}")
    private String bucket;
    @Value("${oss.folder:}")
    private String folder;

    @Override
    protected void beforeDelete(List<Long> ids) {
        List<FileDO> fileList = baseMapper.lambdaQuery().in(FileDO::getId, ids).list();
        if (ObjectUtil.isNull(fileList)) {
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            fileList.forEach(d -> {
                String path = d.getUrl().replace("http://", "").replace("https://", "");
                ossClient.deleteObject(bucket, path.substring(path.indexOf("/") + 1));
            });
            ossClient.shutdown();
        }
    }

    @Override
    @Transactional
    public FileInfo upload(MultipartFile file, String storageCode) throws IOException {
        FileDO fileDO = new FileDO();
        fileDO.setName(FileNameUtil.getPrefix(file.getOriginalFilename()));
        fileDO.setSize(file.getSize());
        fileDO.setExtension(FileUtil.getSuffix(file.getOriginalFilename()));
        fileDO.setType(FileTypeEnum.getByExtension(fileDO.getExtension()));
        save(fileDO);
        String path = String.format("%s/%s.%s", folder, fileDO.getId(), fileDO.getExtension());
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        ossClient.putObject(new PutObjectRequest(bucket, path, file.getInputStream()));
        ossClient.shutdown();
        String url = "http://".concat(bucket).concat(".").concat(endpoint).concat("/").concat(path);
        fileDO.setUrl(url);
        if (FileTypeEnum.IMAGE.getExtensions().contains(FileNameUtil.extName(file.getOriginalFilename()))) {
            fileDO.setThumbnailUrl(url);
            fileDO.setThumbnailSize(file.getSize());
        }
        updateById(fileDO);
        FileInfo info = new FileInfo();
        info.setUrl(url);
        info.setSize(file.getSize());
        info.setFilename(path);
        info.setOriginalFilename(file.getOriginalFilename());
        info.setPath(path);
        info.setContentType(file.getContentType());
        info.setCreateTime(Date.from(fileDO.getCreateTime().atZone(ZoneId.systemDefault()).toInstant()));
        return info;
    }

    @Override
    public Long countByStorageIds(List<Long> storageIds) {
        return baseMapper.lambdaQuery().in(FileDO::getStorageId, storageIds).count();
    }

    @Override
    public FileStatisticsResp statistics() {
        FileStatisticsResp resp = new FileStatisticsResp();
        List<FileStatisticsResp> statisticsList = baseMapper.statistics(UserContextHolder.getUserId());
        if (CollUtil.isEmpty(statisticsList)) {
            return resp;
        }
        resp.setData(statisticsList);
        resp.setSize(statisticsList.stream().mapToLong(FileStatisticsResp::getSize).sum());
        resp.setNumber(statisticsList.stream().mapToLong(FileStatisticsResp::getNumber).sum());
        return resp;
    }

    @Override
    protected <E> List<E> list(FileQuery query, SortQuery sortQuery, Class<E> targetClass) {
        query.setCreateUser(UserContextHolder.getUserId());
        return super.list(query, sortQuery, targetClass);
    }

    @Override
    public PageResp<FileResp> page(FileQuery query, PageQuery pageQuery) {
        query.setCreateUser(UserContextHolder.getUserId());
        return super.page(query, pageQuery);
    }
}